Skip to content

feat: OptiX AI Denoiser — real-time noise reduction#8

Merged
Cle2ment merged 3 commits into
masterfrom
feat/optix-denoiser
Jun 4, 2026
Merged

feat: OptiX AI Denoiser — real-time noise reduction#8
Cle2ment merged 3 commits into
masterfrom
feat/optix-denoiser

Conversation

@Cle2ment
Copy link
Copy Markdown
Owner

@Cle2ment Cle2ment commented Jun 4, 2026

Summary

Integrates NVIDIA OptiX AI Denoiser for real-time noise reduction in the GPU path tracer. RGB-only denoising (HDR model), activated via ImGui "Denoise" checkbox.

How It Works

  1. PostProcessKernel writes averaged HDR float4 to a new d_DenoiseBuffer
  2. OptiXDenoiser runs spatial denoising on this buffer (GPU-side, on compute stream)
  3. ConvertToRGBAKernel converts denoised float4 → RGBA8
  4. Results downloaded as normal

Build

Requires OptiX SDK 9.x (OptiX_ROOT env var or auto-detection from C:\ProgramData\NVIDIA Corporation\OptiX SDK *). Without SDK: #ifdef WL_OPTIX guard, stub class, no-op — project builds identically.

Changes (3 commits)

Commit Description
4ebc220 xmake OptiX SDK detection + WL_OPTIX build flag
729d026 OptiXDenoiser RAII wrapper class (stub for non-OptiX)
cb05cd2 Pipeline integration: denoise buffer, ConvertToRGBAKernel, ImGui toggle

Files

File +/− Notes
OptiXDenoiser.h +67 RAII wrapper + stub
OptiXDenoiser.cpp +177 OptiX context, denoiser lifecycle
CUDARenderer.cuh +27 ConvertToRGBAKernel, denoiseBuffer param
CUDARenderer.cu +51 d_DenoiseBuffer, CUDARenderer_DenoiseOutput
CUDARenderer.h +12 New API declarations
Renderer.h +8 OptiXDenoiser member, EnableDenoising setting
Renderer.cpp +18 Denoise pass in RenderGPU
WalnutApp.cpp +5 ImGui "Denoise" checkbox
xmake.lua +33 OptiX detection, Advapi32 link, NOMINMAX

Verification

  • ✅ Full build passes with OptiX SDK 9.1.0 + CUDA 13.3 + MSVC
  • ✅ Build passes without OptiX SDK (stub mode)
  • ✅ Tasks 3+4 combined into single commit (tightly coupled)
  • ⚠️ Runtime visual verification needed (manual)

Copilot AI review requested due to automatic review settings June 4, 2026 06:40
@Cle2ment
Copy link
Copy Markdown
Owner Author

Cle2ment commented Jun 4, 2026

LGTM :D

@Cle2ment Cle2ment merged commit f4d3c20 into master Jun 4, 2026
3 checks passed
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Integrates an NVIDIA OptiX-based denoising pass into the CUDA renderer path to reduce real-time noise, with build-time SDK detection and an ImGui toggle to enable/disable denoising.

Changes:

  • Adds OptiX SDK detection to xmake and gates denoiser compilation behind WL_OPTIX.
  • Introduces an OptiXDenoiser RAII wrapper and wires it into the GPU render loop.
  • Adds a GPU-side HDR denoise buffer plus a conversion kernel to write denoised results back to the RGBA8 output.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
xmake.lua Detects OptiX SDK and enables WL_OPTIX, adds include/link settings for OptiX integration.
RayTracing/src/WalnutApp.cpp Adds ImGui “Denoise” checkbox (guarded by WL_OPTIX).
RayTracing/src/Renderer.h Adds denoiser setting/member (and OptiX header include).
RayTracing/src/Renderer.cpp Runs OptiX denoise + reconvert pass after CUDA rendering.
RayTracing/src/OptiXDenoiser.h Declares OptiX denoiser RAII wrapper (and stub interface when disabled).
RayTracing/src/OptiXDenoiser.cpp Implements OptiX context/denoiser lifecycle and per-frame invoke.
RayTracing/src/CUDARenderer.h Exposes denoise buffer + stream accessors and denoised-to-RGBA conversion API.
RayTracing/src/CUDARenderer.cuh Writes averaged HDR output to a denoise buffer and adds ConvertToRGBAKernel.
RayTracing/src/CUDARenderer.cu Allocates denoise buffer and implements new denoise/stream helper APIs.

Comment thread RayTracing/src/Renderer.h
Comment on lines +19 to +21
#ifdef WL_OPTIX
#include "OptiXDenoiser.h"
#endif
Comment on lines +552 to +555
cudaStream_t stream = (cudaStream_t)CUDARenderer_GetComputeStream(m_CUDAState);
if (!m_Denoiser.IsValid())
m_Denoiser.Initialize(width, height, stream);

Comment on lines +314 to +325
void CUDARenderer_ConvertDenoisedToRGBA(CUDARenderState* state, cudaStream_t stream)
{
if (!state || !state->initialized || state->pixelCount == 0) return;

int threads = 256;
int blocks = (state->pixelCount + threads - 1) / threads;
ConvertToRGBAKernel<<<blocks, threads, 0, stream>>>(
(const float4*)state->d_DenoiseBuffer,
state->d_OutputImage,
state->pixelCount
);
}
Comment on lines +36 to +49
// Retrieve current CUDA context (must already exist)
CUcontext cuCtx = nullptr;
CUresult cuRes = cuCtxGetCurrent(&cuCtx);
if (cuRes != CUDA_SUCCESS || cuCtx == nullptr)
{
CUdevice cuDevice;
cuCtxGetDevice(&cuDevice);
cuRes = cuDevicePrimaryCtxRetain(&cuCtx, cuDevice);
if (cuRes != CUDA_SUCCESS)
{
std::fprintf(stderr, "[OptiX] Failed to get CUDA context\n");
return;
}
}
Comment on lines +87 to +106
OPTIX_CHECK(optixDenoiserCreate(
m_optixContext, OPTIX_DENOISER_MODEL_KIND_HDR,
&opts, &m_denoiser));

if (!m_denoiser) return false;

OPTIX_CHECK(optixDenoiserComputeMemoryResources(
m_denoiser, width, height, &m_sizes));

cudaMalloc(&m_dStateBuffer, m_sizes.stateSizeInBytes);
cudaMalloc(&m_dScratchBuffer, m_sizes.withoutOverlapScratchSizeInBytes);
cudaMalloc(&m_dHdrIntensity, sizeof(float));

OPTIX_CHECK(optixDenoiserSetup(
m_denoiser, (CUstream)stream,
width, height,
(CUdeviceptr)m_dStateBuffer, m_sizes.stateSizeInBytes,
(CUdeviceptr)m_dScratchBuffer, m_sizes.withoutOverlapScratchSizeInBytes));

m_valid = true;
@Cle2ment Cle2ment deleted the feat/optix-denoiser branch June 5, 2026 02:31
@Cle2ment Cle2ment restored the feat/optix-denoiser branch June 5, 2026 02:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants